package com.onlineMIS.ORM.DAO.headQ.inventory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.onlineMIS.ORM.DAO.Response;
import com.onlineMIS.ORM.DAO.chainS.user.ChainUserInforService;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.BrandDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.CategoryDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.ProductBarcodeDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.QuarterDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.YearDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.inventory.HeadQInventoryFlowOrderDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.inventory.HeadQInventoryFlowOrderProductDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.inventory.HeadQInventoryStoreDAOImpl;
import com.onlineMIS.ORM.DAO.headQ.user.UserInforDaoImpl;
import com.onlineMIS.ORM.entity.base.BaseOrder;
import com.onlineMIS.ORM.entity.base.Pager;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInOutStock;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInOutStockArchive;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInvenTraceInfoVO;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInventoryFlowOrder;
import com.onlineMIS.ORM.entity.chainS.inventoryFlow.ChainInventoryReportTemplate;
import com.onlineMIS.ORM.entity.chainS.sales.ChainStoreSalesOrder;
import com.onlineMIS.ORM.entity.chainS.user.ChainStore;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Brand;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Category;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Color;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Product;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.ProductBarcode;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Quarter;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.Year;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadQInventoryStock;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadQInventoryStore;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInvenFlowOrderVO;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInvenTraceInfoVO;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryReportTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.InventoryFileTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryFlowOrderTemplate;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryFlowOrder;
import com.onlineMIS.ORM.entity.headQ.inventory.HeadqInventoryFlowOrderProduct;
import com.onlineMIS.ORM.entity.headQ.user.UserInfor;
import com.onlineMIS.action.headQ.inventoryFlow.HeadqInventoryFlowFormBean;
import com.onlineMIS.action.headQ.inventoryFlow.HeadqInventoryFlowUIBean;
import com.onlineMIS.common.Common_util;
import com.onlineMIS.common.ExcelUtil;
import com.onlineMIS.common.loggerLocal;
import com.onlineMIS.sorter.ChainInventoryReportSort;

@Service
public class HeadqInventoryService {
	@Autowired
	private HeadQInventoryStockDAOImpl headQInventoryStockDAOImpl;
	@Autowired
	private YearDaoImpl yearDaoImpl;
	@Autowired
	private QuarterDaoImpl quarterDaoImpl;
	@Autowired
	private BrandDaoImpl brandDaoImpl;
	@Autowired
	private ProductBarcodeDaoImpl productBarcodeDaoImpl;
	@Autowired
	private HeadQInventoryStoreDAOImpl headQInventoryStoreDAOImpl;

	@Autowired
	private HeadQInventoryFlowOrderProductDAOImpl headqInventoryFlowOrderProductDaoImpl;
	@Autowired
	private HeadQInventoryFlowOrderDAOImpl headqInventoryFlowOrderDaoImpl;

	
	@Autowired
	CategoryDaoImpl categoryDaoImpl;
	
	@Autowired
	private UserInforDaoImpl userInforDaoImpl;
    
    		
	/**
	 * 获取总部的库存状况
	 * 
	 * @param parentId
	 * @param storeId
	 * @param yearId
	 * @param quarterId
	 * @param brandId
	 * @return
	 */
	@Transactional
	public Response getHeadqInventory(int parentId, int storeId, int yearId, int quarterId, int brandId,
			int categoryLevelId, int categoryId, int rptTypeId) {
		System.out.println(storeId + "," + yearId + "," + quarterId + "," + brandId);
		Response response = new Response();
		List<HeadqInventoryVO> headqInventoryVOList = new ArrayList<HeadqInventoryVO>();

		if (yearId == 0) {
			// @2. 展开所有年份的库存信息
			String hql;
			List<Object> inventoryData = new ArrayList<Object>();

			if (storeId != Common_util.ALL_RECORD) {
				hql = "SELECT his.productBarcode.product.year.year_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? GROUP BY his.productBarcode.product.year.year_ID ORDER BY his.productBarcode.product.year.year_ID ASC";
				Object[] values = { storeId };
				inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
			} else {
				hql = "SELECT his.productBarcode.product.year.year_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE 1 = 1 GROUP BY his.productBarcode.product.year.year_ID ORDER BY his.productBarcode.product.year.year_ID ASC";
				inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, null, null, true);
			}

			if (inventoryData != null) {
				for (Object object : inventoryData) {
					Object[] object2 = (Object[]) object;
					int yearIdDB = Common_util.getInt(object2[0]);
					double costTotal = Common_util.getDouble(object2[1]);
					int quantity = Common_util.getInt(object2[2]);

					Year year = yearDaoImpl.get(yearIdDB, true);

					HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, year.getYear() + "年", quantity,
							costTotal, HeadqInventoryVO.STATE_CLOSED, storeId, yearIdDB, quarterId, brandId, categoryId,
							categoryLevelId);
					headqInventoryVOList.add(headqInventoryVO);
				}
			}
		} else if (quarterId == 0) {
			// @2. 展开所有季的库存信息
			String hql;
			List<Object> inventoryData = new ArrayList<Object>();
			if (storeId != Common_util.ALL_RECORD) {
				hql = "SELECT his.productBarcode.product.quarter.quarter_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND his.productBarcode.product.year.year_ID=? GROUP BY his.productBarcode.product.quarter.quarter_ID ORDER BY his.productBarcode.product.quarter.quarter_ID ASC";
				Object[] values = { storeId, yearId };
				inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
			} else {
				hql = "SELECT his.productBarcode.product.quarter.quarter_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.productBarcode.product.year.year_ID=? GROUP BY his.productBarcode.product.quarter.quarter_ID ORDER BY his.productBarcode.product.quarter.quarter_ID ASC";
				Object[] values = { yearId };
				inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
			}

			if (inventoryData != null) {
				for (Object object : inventoryData) {
					Object[] object2 = (Object[]) object;
					int quarterIdDB = Common_util.getInt(object2[0]);
					double costTotal = Common_util.getDouble(object2[1]);
					int quantity = Common_util.getInt(object2[2]);

					Year year = yearDaoImpl.get(yearId, true);
					Quarter quarter = quarterDaoImpl.get(quarterIdDB, true);

					String name = year.getYear() + "年" + quarter.getQuarter_Name();

					HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity, costTotal,
							HeadqInventoryVO.STATE_CLOSED, storeId, yearId, quarterIdDB, brandId, categoryId,
							categoryLevelId);
					headqInventoryVOList.add(headqInventoryVO);
				}
			}
		} else {
			// by brand
			if (rptTypeId == 1) {
				if (brandId == 0) {
					// @2. 展开所有品霞的库存信息
					String hql;
					List<Object> inventoryData = new ArrayList<Object>();

					if (storeId != Common_util.ALL_RECORD) {
						hql = "SELECT his.productBarcode.product.brand.brand_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? GROUP BY his.productBarcode.product.brand.brand_ID ORDER BY his.productBarcode.product.brand.brand_ID ASC";
						Object[] values = { storeId, yearId, quarterId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					} else {
						hql = "SELECT his.productBarcode.product.brand.brand_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE  his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? GROUP BY his.productBarcode.product.brand.brand_ID ORDER BY his.productBarcode.product.brand.brand_ID ASC";
						Object[] values = { yearId, quarterId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					}

					if (inventoryData != null) {
						for (Object object : inventoryData) {
							Object[] object2 = (Object[]) object;
							int brandIdDB = Common_util.getInt(object2[0]);
							double costTotal = Common_util.getDouble(object2[1]);
							int quantity = Common_util.getInt(object2[2]);

							Brand brand = brandDaoImpl.get(brandIdDB, true);

							String name = "";
							String pinyin = brand.getPinyin();
							if (!StringUtils.isEmpty(pinyin)) {
								name = pinyin.substring(0, 1) + " ";
							}

							name = brand.getBrand_Name();

							HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity,
									costTotal, HeadqInventoryVO.STATE_CLOSED, storeId, yearId, quarterId, brandIdDB,
									categoryId, categoryLevelId);
							headqInventoryVOList.add(headqInventoryVO);
						}
					}
				} else if (brandId != 0) {
					// @2. 展开当前品霞的库存信息
					String hql;
					List<Object> inventoryData = new ArrayList<Object>();

					if (storeId != Common_util.ALL_RECORD) {
						hql = "SELECT his.productBarcode.id, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND his.productBarcode.product.brand.brand_ID=?  GROUP BY his.productBarcode.id ORDER BY his.productBarcode.product.productCode ASC ";
						Object[] values = { storeId, yearId, quarterId, brandId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					} else {
						hql = "SELECT his.productBarcode.id, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND his.productBarcode.product.brand.brand_ID=?  GROUP BY his.productBarcode.id ORDER BY his.productBarcode.product.productCode ASC ";
						Object[] values = { yearId, quarterId, brandId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					}

					if (inventoryData != null) {
						for (Object object : inventoryData) {
							Object[] object2 = (Object[]) object;
							int pbId = Common_util.getInt(object2[0]);
							double costTotal = Common_util.getDouble(object2[1]);
							int quantity = Common_util.getInt(object2[2]);

							ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);
							Color color = pb.getColor();
							String colorName = "";
							if (color != null)
								colorName = color.getName();
							Product product = pb.getProduct();
							String gender = "";
							String sizeRange = "";

							Category category = product.getCategory();
							String name = Common_util.cutProductCode(pb.getProduct().getProductCode()) + colorName + " "
									+ gender + sizeRange + category.getCategory_Name();

							HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity,
									costTotal, HeadqInventoryVO.STATE_OPEN, storeId, yearId, quarterId, brandId,
									categoryId, categoryLevelId);
							headqInventoryVO.setPbId(pbId);
							headqInventoryVOList.add(headqInventoryVO);
						}
					}
				}
			} else if (rptTypeId == 2) {

				if (categoryLevelId == 0) {
					// @2. 展开所有品霞的库存信息
					String hql;
					List<Object> inventoryData = new ArrayList<Object>();
					if (storeId != Common_util.ALL_RECORD) {
						hql = "SELECT his.productBarcode.product.categoryLevel1.category_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? GROUP BY his.productBarcode.product.categoryLevel1.category_ID";
						Object[] values = { storeId, yearId, quarterId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					} else {
						hql = "SELECT his.productBarcode.product.categoryLevel1.category_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE  his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? GROUP BY his.productBarcode.product.categoryLevel1.category_ID";
						Object[] values = { yearId, quarterId };
						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					}

					if (inventoryData != null) {
						for (Object object : inventoryData) {
							Object[] object2 = (Object[]) object;
							int categoryLevel1Id = Common_util.getInt(object2[0]);
							double costTotal = Common_util.getDouble(object2[1]);
							int quantity = Common_util.getInt(object2[2]);

							Category catgory = categoryDaoImpl.get(categoryLevel1Id, true);
							String name = catgory.getCategory_Name();

							HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity,
									costTotal, HeadqInventoryVO.STATE_CLOSED, storeId, yearId, quarterId, brandId,
									categoryId, categoryLevel1Id);
							headqInventoryVOList.add(headqInventoryVO);
						}
					}
				} else if (categoryId == 0) {

					// @2. 展开所有品霞的库存信息 表示 categoryLevel1 != 0

					String hql;
					List<Object> inventoryData = new ArrayList<Object>();

					if (storeId != Common_util.ALL_RECORD) {
						hql = "SELECT his.productBarcode.product.category.category_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND  his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND his.productBarcode.product.categoryLevel1.category_ID=? GROUP BY his.productBarcode.product.category.category_ID";
						Object[] values = { storeId, yearId, quarterId, categoryLevelId };

						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					} else {
						hql = "SELECT his.productBarcode.product.category.category_ID, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND his.productBarcode.product.categoryLevel1.category_ID=? GROUP BY his.productBarcode.product.category.category_ID";
						Object[] values = { yearId, quarterId, categoryLevelId };

						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					}

					if (inventoryData != null) {
						for (Object object : inventoryData) {
							Object[] object2 = (Object[]) object;
							int categoryIdDB = Common_util.getInt(object2[0]);
							double costTotal = Common_util.getDouble(object2[1]);
							int quantity = Common_util.getInt(object2[2]);

							Category catgory = categoryDaoImpl.get(categoryIdDB, true);
							String name = catgory.getCategory_Name();

							HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity,
									costTotal, HeadqInventoryVO.STATE_CLOSED, storeId, yearId, quarterId, brandId,
									categoryIdDB, categoryLevelId);
							headqInventoryVOList.add(headqInventoryVO);
						}
					}
				} else {
					// @2. 展开当前品霞的库存信息
					String hql;
					List<Object> inventoryData = new ArrayList<Object>();
					if (storeId != Common_util.ALL_RECORD) {
						hql = "SELECT his.productBarcode.id, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE his.storeId = ? AND his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND  his.productBarcode.product.categoryLevel1.category_ID=? AND his.productBarcode.product.category.category_ID=? GROUP BY his.productBarcode.id";
						Object[] values = { storeId,yearId, quarterId, categoryLevelId, categoryId };

						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					} else {
						hql = "SELECT his.productBarcode.id, SUM(costTotal), SUM(quantity) FROM HeadQInventoryStock AS his WHERE   his.productBarcode.product.year.year_ID=? AND his.productBarcode.product.quarter.quarter_ID=? AND  his.productBarcode.product.categoryLevel1.category_ID=? AND his.productBarcode.product.category.category_ID=? GROUP BY his.productBarcode.id";
						Object[] values = { yearId, quarterId, categoryLevelId, categoryId };

						inventoryData = headQInventoryStockDAOImpl.executeHQLSelect(hql, values, null, true);
					}

					if (inventoryData != null) {
						for (Object object : inventoryData) {
							Object[] object2 = (Object[]) object;
							int pbId = Common_util.getInt(object2[0]);
							double costTotal = Common_util.getDouble(object2[1]);
							int quantity = Common_util.getInt(object2[2]);

							ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);
							Color color = pb.getColor();
							String colorName = "";
							if (color != null)
								colorName = color.getName();

							Brand brand = pb.getProduct().getBrand();
							String name = Common_util.cutProductCode(pb.getProduct().getProductCode()) + colorName + " "
									+ brand.getBrand_Name();

							HeadqInventoryVO headqInventoryVO = new HeadqInventoryVO(parentId, name, quantity,
									costTotal, HeadqInventoryVO.STATE_OPEN, storeId, yearId, quarterId, brandId,
									categoryId, categoryLevelId);
							headqInventoryVO.setPbId(pbId);
							headqInventoryVOList.add(headqInventoryVO);

						}
					}
				}
			}
		}

		response.setReturnValue(headqInventoryVOList);
		return response;
	}

	/**
	 * 生成excel的inventory 报表
	 * @param storeId
	 * @param yearId
	 * @param quarterId
	 * @param brandId
	 * @param string
	 * @return
	 * @throws IOException 
	 */
	public Response generateInventoryExcelReport(int storeId, int yearId, int quarterId, int brandId, String templatePath)  {
		Response response = new Response();
		
		HeadQInventoryStore store = null;
		if (storeId != Common_util.ALL_RECORD){
			store = headQInventoryStoreDAOImpl.get(storeId, true);
		}
		
		/**
		 * @1. 准备数据库数据
		 */
		List<HeadqInventoryReportItem> reportItems = new ArrayList<HeadqInventoryReportItem>();
		
		
		StringBuffer hql = new StringBuffer("SELECT his.productBarcode.id, SUM(quantity), SUM(costTotal) FROM HeadQInventoryStock AS his WHERE 1=1");
		
		
		if (brandId != 0){
			hql.append(" AND his.productBarcode.product.brand.brand_ID=" + brandId);
		} 

		if (quarterId != 0){
			hql.append(" AND his.productBarcode.product.quarter.quarter_ID=" + quarterId);
		} 
		
		if (yearId != 0){
			hql.append(" AND his.productBarcode.product.year.year_ID=" + yearId);
		} 
		
		if (storeId  != Common_util.ALL_RECORD){
			hql.append(" AND his.storeId=" + storeId);
		}
		
		hql.append("GROUP BY his.productBarcode.id");

		List<Object> result = headQInventoryStockDAOImpl.executeHQLSelect(hql.toString(), null, null, true);
		for (int i = 0; i < result.size(); i++){
			  Object object = result.get(i);
			  if (object != null){
				  HeadqInventoryReportItem item = new HeadqInventoryReportItem();
				  
				 Object[] recordResult = (Object[])object;
				 int productId = Common_util.getInt(recordResult[0]);
				 int quantity = Common_util.getInt(recordResult[1]);
				 double cost = Common_util.getDouble(recordResult[2]);
				 
				 if (quantity == 0)
					 continue;
				 item.setTotalQuantity(quantity);
				 item.setTotalCostAmt(cost);
				 
				 ProductBarcode productBarcode = productBarcodeDaoImpl.get(productId, true);

				 item.setProductBarcode(productBarcode);
				 
				 reportItems.add(item);
			  }
		}
		
		//Collections.sort(reportItems, new HeadqInventoryReportSort());
		HeadqInventoryReportTemplate headqInventoryReportTemplate;
		try {
			headqInventoryReportTemplate = new HeadqInventoryReportTemplate(reportItems, store, templatePath);
			HSSFWorkbook wb = headqInventoryReportTemplate.process();
			
			ByteArrayInputStream byteArrayInputStream = ExcelUtil.convertExcelToInputStream(wb);
			
			response.setReturnValue(byteArrayInputStream);
			response.setReturnCode(Response.SUCCESS);
		} catch (IOException e) {
			response.setFail(e.getMessage());
			e.printStackTrace();
		}

		return response;
	}

	/**
	 * 获取库存跟踪信息
	 * 
	 * @param storeId
	 * @param pbId
	 * @return
	 */
	public Response getInventoryTraceInfor(int storeId, int pbId) {
		Response response = new Response();
		Map data = new HashMap<String, List>();
		List<HeadqInvenTraceInfoVO> traceVOs = new ArrayList<HeadqInvenTraceInfoVO>();
		List<HeadqInvenTraceInfoVO> footers = new ArrayList<HeadqInvenTraceInfoVO>();

		if (pbId != 0) {
			DetachedCriteria criteria1 = DetachedCriteria.forClass(HeadQInventoryStock.class);
			criteria1.add(Restrictions.eq("storeId", storeId));
			criteria1.add(Restrictions.eq("productBarcode.id", pbId));
			criteria1.addOrder(Order.asc("date"));
			List<HeadQInventoryStock> stocks = headQInventoryStockDAOImpl.getByCritera(criteria1, true);

			for (HeadQInventoryStock stock : stocks) {
			    HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(storeId, false);
				HeadqInvenTraceInfoVO traceVO = new HeadqInvenTraceInfoVO(stock,store.getName());
				traceVOs.add(traceVO);
			}

			// 建设foot
			HeadqInvenTraceInfoVO foot = new HeadqInvenTraceInfoVO();
			int stockInventory = 0;
			for (HeadqInvenTraceInfoVO ele : traceVOs) {
				stockInventory += ele.getQuantity();
			}

			ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);
			String productName = pb.getProduct().getBrand().getBrand_Name() + " " + pb.getProduct().getProductCode();
			Color color = pb.getColor();
			if (color != null)
				productName += color.getName();

			foot.setDate(productName);
			foot.setQuantity(stockInventory);
			footers.add(foot);

			response.setReturnCode(Response.SUCCESS);
		}

		data.put("rows", traceVOs);
		data.put("footer", footers);
		response.setReturnValue(data);

		return response;
	}

	/**
	 * 
	 * @param formBean
	 */
	public void prepareCreateOrderUI(HeadqInventoryFlowFormBean formBean,HeadqInventoryFlowUIBean uiBean, UserInfor loginUser) {
		//2. set the creator
		formBean.getFlowOrder().setCreator(loginUser);
		
		//3. set the date
		formBean.getFlowOrder().setOrderDate(new Date());
		
		List<HeadQInventoryStore> stores = headQInventoryStoreDAOImpl.getAll(true);
		uiBean.setStores(stores);
		
	}

	/**
	 * 在inventory flow order上 scan barcode
	 * 
	 * @param barcode
	 * @param indexPage
	 * @param fromSrc
	 * @return
	 */
	public Response scanByBarcodeInvenOrder(String barcode, int indexPage, int fromSrc, int storeId) {
		Response response = new Response();
		ProductBarcode pb = productBarcodeDaoImpl.getByBarcode(barcode);

		if (pb != null) {

			productBarcodeDaoImpl.evict(pb);

			int inventoryLevel = 0;

			try {
				HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(storeId, true);
				inventoryLevel = headQInventoryStockDAOImpl.getProductStock(pb.getId(), storeId, true);
			} catch (Exception e) {
				String msg = "获取inventory出错," + pb.getId() + "," + storeId;
				loggerLocal.info(msg);
				response.setFail(msg);
				return response;
			}

			HeadqInventoryFlowProductVO productVO = new HeadqInventoryFlowProductVO(pb, inventoryLevel, indexPage);
			response.setReturnValue(productVO);

			return response;
		} else {
			return null;
		}

	}
	
	
	/**
	 * function to save the flow order to final 过账
	 * 
	 * @param flowOrder
	 * @param loginUser
	 * @throws Exception
	 */
	@Transactional
	public Response saveToFinal(HeadqInventoryFlowOrder order, UserInfor loginUser) throws Exception {
//		int status_org = flowOrder.getStatus();
		int status_org = 0;
		Response response = new Response();
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			if (order.getType() == HeadqInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
				order.setStoreId(order.getFromStore().getId());
			} else {
				order.setStoreId(order.getStoreId());
			}
			
			
			order.setStatus(HeadqInventoryFlowOrder.STATUS_COMPLETE);

			// 1. save the order to final 过账
			save(order, loginUser);
			// 总部 报溢 报损 库存转移

			List<HeadqInventoryFlowOrderProduct> productList = order.getProductList();
			for (HeadqInventoryFlowOrderProduct product : productList) {

				int inventoryQ = headQInventoryStockDAOImpl.getProductStock(product.getProductBarcode().getId(),
						order.getStoreId(), true);
				product.setInventoryQ(inventoryQ);

				product.setTotalSalesPrice(
						product.getProductBarcode().getProduct().getSalesPrice() * product.getQuantity());

			}
			// 报溢 报损
			if (order.getType() == HeadqInventoryFlowOrder.FLOW_LOSS_ORDER
					|| order.getType() == HeadqInventoryFlowOrder.OVER_FLOW_ORDER) {
				updateHeadqFlowOrderInOutStock(order, HeadqInventoryFlowOrder.STATUS_COMPLETE);

				// 调货单
			} else if (order.getType() == HeadqInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
				// 库存转移业务逻辑
				updateChainInvenTransferInOutStock(order, HeadqInventoryFlowOrder.STATUS_COMPLETE);
			}

			response.setReturnCode(Response.SUCCESS);
			response.setMessage("已经成功保存");
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("保存单据失败");
		}

		return response;
	}
	
	
	
	
	
	/**
	 * add the general save information
	 * 
	 * @param flowOrder
	 * @param loginUser
	 * @throws Exception
	 */
	@Transactional
	public HeadqInventoryFlowOrder save(HeadqInventoryFlowOrder flowOrder, UserInfor loginUser) throws Exception {
		flowOrder.setOrderDate(new Date());
		flowOrder.setCreator(loginUser);

		// 1. to group the product list
		groupProductList(flowOrder);

		// 2. 检查是否toChainStore
		HeadQInventoryStore toChainStore = flowOrder.getToStore();
		if (toChainStore != null) {
			flowOrder.setToStore(toChainStore);

		}
		// 3. 检查是否fromChainStore
		HeadQInventoryStore fromChainStore = flowOrder.getFromStore();
		if (fromChainStore != null)
			flowOrder.setFromStore(fromChainStore);

		// 4. 注入 chainStore
		// 如果是调库存单，需要注入chainStore.首先fromChainStore,然后toChainStore
		if (flowOrder.getType() == HeadqInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
			if (fromChainStore != null && fromChainStore.getId() != 0)
				flowOrder.setFromStore(fromChainStore);

			else if (toChainStore != null && toChainStore.getId() != 0)
				flowOrder.setToStore(toChainStore);
			else
				throw new Exception("无法找到调货单的发起人");
		}

		flowOrder.buildIndex();
		flowOrder.putListToSet();

		int orderId = flowOrder.getId();

		if (orderId != 0) {
			HeadqInventoryFlowOrder originalOrder = getOrderById(orderId, loginUser);

			//orderId@orderProductId
			//123@2345
			List<String> newProducts = getProductIds(flowOrder);
			List<String> originalProducts = getProductIds(originalOrder);
			List<String> deletedProducts = new ArrayList<String>();
			for (String id : originalProducts) {
				if (!newProducts.equals(id))
					deletedProducts.add(id);
			}
			headqInventoryFlowOrderProductDaoImpl.deleteProducts(deletedProducts);

			headqInventoryFlowOrderDaoImpl.evict(originalOrder);

			headqInventoryFlowOrderDaoImpl.saveOrUpdate(flowOrder, false);
		} else {
			headqInventoryFlowOrderDaoImpl.save(flowOrder, false);
		}

		return flowOrder;

	}
	
	
	
	/**
	 * function to updat the chain stock in/out level
	 * 
	 * @param order
	 * @param statusCancel
	 * @throws Exception
	 */
	private void updateHeadqFlowOrderInOutStock(HeadqInventoryFlowOrder order, int status) {
		boolean isCancel = false;
		int orderType = order.getType();

		if (status == HeadqInventoryFlowOrder.STATUS_CANCEL)
			isCancel = true;

		String orderId = String.valueOf(order.getId());
		int offset = isCancel ? -1 : 1;
		String orderIdHead = isCancel ? "C" : "";

		if (orderType == HeadqInventoryFlowOrder.FLOW_LOSS_ORDER) {
			orderId = HeadQInventoryStock.CHAIN_FLOWLOSS + orderIdHead + orderId;
			offset *= -1;
		} else if (orderType == HeadqInventoryFlowOrder.OVER_FLOW_ORDER) {
			orderId = HeadQInventoryStock.CHAIN_OVERFLOW + orderIdHead + orderId;
//		} else if (orderType == HeadqInventoryFlowOrder.INVENTORY_ORDER) {
//			orderId = HeadQInventoryStock.CHAIN_OVERFLOW + orderIdHead + orderId;
		} else
			return;

		Iterator<HeadqInventoryFlowOrderProduct> orderProducts = order.getProductSet().iterator();
		while (orderProducts.hasNext()) {
			HeadqInventoryFlowOrderProduct orderProduct = orderProducts.next();

			ProductBarcode pBarcode = productBarcodeDaoImpl.get(orderProduct.getProductBarcode().getId(), true);
			Product product = pBarcode.getProduct();

			int quantity = orderProduct.getQuantity() * offset;

			double cost = product.getRecCost();

			// 批发价格
			double salePrice = ProductBarcodeDaoImpl.getWholeSalePrice(pBarcode);

			double chainSalePrice = pBarcode.getProduct().getSalesPrice();
			HeadQInventoryStock inOutStock = new HeadQInventoryStock(order.getStoreId(),
					orderProduct.getProductBarcode(), orderId, quantity, cost * quantity, salePrice,
					salePrice * quantity, chainSalePrice * quantity);
			headQInventoryStockDAOImpl.save(inOutStock, false);
		}
	}
	
	
	
	
	/**
	 * 调库产生的库存需要修改
	 * 
	 * @param order
	 * @param status
	 */
	private void updateChainInvenTransferInOutStock(HeadqInventoryFlowOrder order, int status) {
		boolean isCancel = false;
		HeadQInventoryStore fromChainStore = order.getFromStore();
		HeadQInventoryStore toChainStore = order.getToStore();

		int fromClientId = fromChainStore.getId();
		int toClientId = toChainStore.getId();

		if (fromClientId == 0 && toClientId == 0)
			loggerLocal.error("调货单据的调出客户和调入客户ID不能同时为零. 单据号" + order.getId());

		if (status == HeadqInventoryFlowOrder.STATUS_CANCEL)
			isCancel = true;

		String orderId = String.valueOf(order.getId());
		int offset = isCancel ? -1 : 1;
		String orderIdHead = isCancel ? "C" : "";

		orderId = HeadQInventoryStock.HEAD_TRANSFER + orderIdHead + orderId;

		Iterator<HeadqInventoryFlowOrderProduct> orderProducts = order.getProductSet().iterator();
		while (orderProducts.hasNext()) {
			HeadqInventoryFlowOrderProduct orderProduct = orderProducts.next();

			int productId = orderProduct.getProductBarcode().getId();
			String barcode = orderProduct.getProductBarcode().getBarcode();
			int quantity = orderProduct.getQuantity() * offset;

			/**
			 * 1. 为from chain准备库存调出
			 */
			double cost = 0;

			ProductBarcode pBarcode = productBarcodeDaoImpl.get(productId, true);
			double salePrice = pBarcode.getProduct().getSalesPrice();

			double chainSalePrice = pBarcode.getProduct().getSalesPrice();

			if (fromClientId > 0) {
				// to get the latest cost for from wholesaler
				int fromQuantity = -1 * quantity;
//				 HeadQSalesHistoryId historyId = new HeadQSalesHistoryId(productId, fromClientId);
//				 HeadQSalesHistory priorHistory = headQSalesHisDAOImpl.get(historyId, true);
//
//				 if (priorHistory != null)
//					 cost = priorHistory.getWholePrice();
//				 else {
//					 loggerLocal.error(ERRORS.ERROR_NO_COST + " 找不到货品进价: " + fromClientId + "," + barcode + "," + productId + "," + orderProduct.getProductBarcode().getProduct().getProductCode());
//					 cost = productBarcodeDaoImpl.getWholeSalePrice(pBarcode);
//				 }

				HeadQInventoryStock inOutStock = new HeadQInventoryStock(fromClientId, orderProduct.getProductBarcode(),
						orderId, quantity * -1, cost * quantity, salePrice, salePrice * quantity, chainSalePrice * quantity);
				headQInventoryStockDAOImpl.save(inOutStock, false);
			} else
				cost = productBarcodeDaoImpl.getWholeSalePrice(pBarcode);

			/**
			 * 为to chain store准备库存调入单, 和saleshistory
			 */
			if (toClientId > 0) {
				// 1. 更新in-out
				int toQuantity = quantity;
				HeadQInventoryStock inOutStock = new HeadQInventoryStock(toClientId, orderProduct.getProductBarcode(),
						orderId, quantity, cost * quantity, salePrice, salePrice * quantity, chainSalePrice * quantity);
				headQInventoryStockDAOImpl.save(inOutStock, false);

//				 //2. 更新history以后合并系统可以
//				 HeadQSalesHistory salesHistory = new HeadQSalesHistory(pBarcode.getId(), toClientId, 0 , cost, 0, toQuantity, 0, 1);
//				 headQSalesHisDAOImpl.saveOrUpdate(salesHistory, false);

			}
		}
	}
	
	
	
	/**
	 * function to group the flow order's product list
	 * 
	 * @param flowOrder
	 * @throws Exception
	 */
	private void groupProductList(HeadqInventoryFlowOrder flowOrder) {
		List<HeadqInventoryFlowOrderProduct> productList = flowOrder.getProductList();

		// to store the sequence product id list
		Set<String> barcodes = new LinkedHashSet<String>();
		Set<Integer> pbIds = new LinkedHashSet<Integer>();

		// list of the post-group
		List<HeadqInventoryFlowOrderProduct> productList2 = new ArrayList<HeadqInventoryFlowOrderProduct>();

		// 1. to group the quantity
		Map<String, HeadqInventoryFlowOrderProduct> productMap = new HashMap<String, HeadqInventoryFlowOrderProduct>();
		int totalProductQ = 0;
		int totalInventoryLevel = 0;
		for (HeadqInventoryFlowOrderProduct orderProduct : productList) {
			if (orderProduct != null) {
				ProductBarcode productBarcode = orderProduct.getProductBarcode();
				if (productBarcode != null) {
					String barcode = productBarcode.getBarcode();
					int productId = productBarcode.getId();
					if (barcode != null && !barcode.equals("") && productId != 0) {
						// 1.1 to make the order product ids
						barcodes.add(barcode);
						pbIds.add(productId);

						// 1.2 to group the product quantity
						int productQ = orderProduct.getQuantity();
						totalProductQ += productQ;
						HeadqInventoryFlowOrderProduct orderProduct2 = productMap.get(barcode);

						if (orderProduct2 != null) {
							int originalQ = orderProduct2.getQuantity();
							orderProduct2.setQuantity(productQ + originalQ);
						} else {
							productMap.put(barcode, orderProduct);
						}
					}
				}
			}
		}
		flowOrder.setTotalQuantity(totalProductQ);

		// 2. calculate the inventory if it is inventory order
		if (flowOrder.getType() == HeadqInventoryFlowOrder.INVENTORY_ORDER) {
			HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(flowOrder.getStoreId(), true);
			Map<String, Integer> inventoryLevelMap = this.getProductsInventoryLevel(pbIds, store.getId());

			// 2.2 to make the new list with inventory level map
			for (String barcode : barcodes) {
				HeadqInventoryFlowOrderProduct orderProduct = productMap.get(barcode);
				Integer inventoryLevel = inventoryLevelMap.get(barcode);
				int inventoryLevel_int = 0;

				if (inventoryLevel != null)
					inventoryLevel_int = inventoryLevel.intValue();

				totalInventoryLevel += inventoryLevel_int;

				if (orderProduct == null) {
					loggerLocal.error("在汇总数据时发生错误");
				} else {
					orderProduct.setInventoryQ(inventoryLevel_int);
					orderProduct.setQuantityDiff(orderProduct.getQuantity() - inventoryLevel_int);
					productList2.add(orderProduct);
				}

			}
			flowOrder.setTotalQuantityDiff(totalProductQ - totalInventoryLevel);
			flowOrder.setTotalInventoryQ(totalInventoryLevel);
		} else {
			// 2.2 to make the new list
			for (String barcode : barcodes) {
				HeadqInventoryFlowOrderProduct orderProduct = productMap.get(barcode);
				if (orderProduct == null) {
					loggerLocal.error("在汇总数据时发生错误");
				} else {
					productList2.add(orderProduct);
				}
			}
		}

		// 3. set the new list
		flowOrder.setProductList(productList2);

	}
	
	
	@Transactional
	public HeadqInventoryFlowOrder getOrderById(int orderId, UserInfor loginUser) {
		HeadqInventoryFlowOrder order = headqInventoryFlowOrderDaoImpl.get(orderId, false);
		headqInventoryFlowOrderDaoImpl.initialize(order);

		order.putSetToList();

		List<HeadqInventoryFlowOrderProduct> productList = order.getProductList();
		for (HeadqInventoryFlowOrderProduct product : productList) {

			int inventoryQ = headQInventoryStockDAOImpl.getProductStock(product.getProductBarcode().getId(),
					order.getStoreId(), true);
			product.setInventoryQ(inventoryQ);

			product.setTotalSalesPrice(
					product.getProductBarcode().getProduct().getSalesPrice() * product.getQuantity());

		}

		return order;
	}
	
	
	/**
	 * to get the product ids
	 * 
	 * @param order
	 * @return
	 */
	private List<String> getProductIds(HeadqInventoryFlowOrder order) {
		String idString = "";
		List<String> originalProducts = new ArrayList<String>();
		if (order != null && order.getProductSet() != null)
			for (HeadqInventoryFlowOrderProduct orderProduct : order.getProductSet()) {
				if (orderProduct != null) {
//					int id = orderProduct.getId();
					idString = orderProduct.getFlowOrder().getId() + "@" + orderProduct.getProductBarcode().getId();
					originalProducts.add(idString);
				}
			}

		return originalProducts;
	}
	
	
	/**
	 * key: 条码 value: 数量
	 * 
	 * @param pbIds
	 * @param storeId
	 * @return
	 */
	public Map<String, Integer> getProductsInventoryLevel(Set<Integer> pbIds, int storeId) {
		Map<Integer, Integer> inventoryFlowMap = new HashMap<Integer, Integer>();

		if (pbIds != null && pbIds.size() > 0) {
			inventoryFlowMap = headQInventoryStockDAOImpl.getProductsInventoryLevel(pbIds, storeId);
		}
//		
//		Map<String, Integer> initialInventoryMap = chainInitialStockDaoImpl.getProductsInventoryLevel(barcodes, clientId);

		Map<String, Integer> stockMap = new HashMap<String, Integer>();

		for (Integer pbId : inventoryFlowMap.keySet()) {
			ProductBarcode pbBarcode = productBarcodeDaoImpl.get(pbId, true);

			stockMap.put(pbBarcode.getBarcode(), inventoryFlowMap.get(pbId));
		}

		return stockMap;

	}
	
	
	/**
	 * function to create the flow order ui bean for create/edit flow order
	 * 
	 * @param loginUser
	 */
	public void prepareCreateFlowOrderFormUIBean(UserInfor loginUser, HeadqInventoryFlowUIBean uiBean,
			HeadqInventoryFlowFormBean formBean, HeadqInventoryFlowOrder order) {
		formBean.setFlowOrder(order);

		DetachedCriteria criteria = DetachedCriteria.forClass(HeadQInventoryStore.class);
		criteria.add(Restrictions.eq("id", order.getStoreId()));

		// 添加仓库信息
		List<HeadQInventoryStore> stores = headQInventoryStoreDAOImpl.getAll(true);
		uiBean.setStores(stores);

		// 2. set the creator
		formBean.getFlowOrder().setCreator(loginUser);

		// 3. set the date
		formBean.getFlowOrder().setOrderDate(new Date());

		// 添加调货仓库信息
		List<HeadQInventoryStore> toStores = headQInventoryStoreDAOImpl.getAll(true);
		uiBean.setToStores(toStores);
		
		// 4. 添加所有货品品类
		List<Category> list = categoryDaoImpl.getAll(true);
		uiBean.setCategorys(list);
	}


	public void prepareSearchFlowOrderUI(HeadqInventoryFlowFormBean formBean, HeadqInventoryFlowUIBean uiBean,
			UserInfor loginUserInfor) {

		uiBean.setInvenOrderTypes(formBean.getFlowOrder().getTypeHQMap());
		uiBean.setInvenOrderStatus(formBean.getFlowOrder().getStatusMap());
		// 添加仓库下拉框信息
		List<HeadQInventoryStore> stores = new ArrayList<HeadQInventoryStore>();

		HeadQInventoryStore headQInventoryStore = new HeadQInventoryStore();
		headQInventoryStore.setId(Common_util.ALL_RECORD);
		headQInventoryStore.setName("所有仓库");
		headQInventoryStore.setComment("所有仓库");
		stores.add(headQInventoryStore);

		stores.addAll(headQInventoryStoreDAOImpl.getAll(true));

		uiBean.setStores(stores);

	}

	/**
	 * 获取总部所有仓库信息
	 * 
	 * @return
	 */
	public Response getHeadqInventoryStore() {
		Response response = new Response();
		List<HeadQInventoryStore> headStores = new ArrayList<HeadQInventoryStore>();
		HeadQInventoryStore headQInventoryStore = new HeadQInventoryStore();
		headQInventoryStore.setId(Common_util.ALL_RECORD);
		headQInventoryStore.setName("总部");
		headQInventoryStore.setComment("所有仓库");
		headStores.add(headQInventoryStore);

		headStores.addAll(headQInventoryStoreDAOImpl.getAll(true));

		response.setReturnValue(headStores);
		response.setReturnCode(Response.SUCCESS);
		return response;
	}

	public void prepareGetStoreInventoryRpt(HeadqInventoryFlowFormBean formBean, HeadqInventoryFlowUIBean uiBean) {
		if (formBean.getStoreId() == Common_util.ALL_RECORD)
			uiBean.setStoreName("所有仓库");
		else {
			HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(formBean.getStoreId(), true);
			uiBean.setStoreName(store.getName());
		}

	}


	/**
	 * function to help search the flow order
	 * 
	 * @param formBean
	 * @param loginUser
	 * @return
	 */
	@Transactional
	public List<HeadqInvenFlowOrderVO> searchInvenFlowOrders(HeadqInventoryFlowFormBean formBean, UserInfor loginUser) {
		boolean cache = false;
		Pager pager = formBean.getPager();

		if (pager.getTotalPage() == 0) {
			DetachedCriteria criteria = buildSearchInvenFlowCriter(formBean);
			criteria.setProjection(Projections.rowCount());
			int totalRecord = Common_util
					.getProjectionSingleValue(headqInventoryFlowOrderDaoImpl.getByCriteriaProjection(criteria, false));
			pager.initialize(totalRecord);
		} else {
			pager.calFirstResult();
			cache = true;
		}

		DetachedCriteria criteria2 = buildSearchInvenFlowCriter(formBean);
		criteria2.addOrder(Order.asc("orderDate"));

		List<HeadqInventoryFlowOrder> headqOrders = headqInventoryFlowOrderDaoImpl.getByCritera(criteria2,
				pager.getFirstResult(), pager.getRecordPerPage(), cache);
		List<HeadqInvenFlowOrderVO> list = new ArrayList<HeadqInvenFlowOrderVO>();

		for (HeadqInventoryFlowOrder order : headqOrders) {

			HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(order.getStoreId(), true);
			UserInfor userInfor = userInforDaoImpl.get(order.getCreator().getUser_id(), true);
				
			
			
			HeadqInvenFlowOrderVO flowOrderVO = new HeadqInvenFlowOrderVO();
			BaseOrder baseOrder = new BaseOrder();

			flowOrderVO.setId(order.getId());
			flowOrderVO.setStoreName(store.getName());
			flowOrderVO.setCreateByName(userInfor.getName());
			flowOrderVO.setTypeChainS(order.getTypeHQS());
			flowOrderVO.setOrderDate(order.getOrderDate());
			flowOrderVO.setComment(order.getComment());
			flowOrderVO.setStatusS(baseOrder.getStatusMap().get(order.getStatus()));
			flowOrderVO.setStatus(order.getStatus());

			flowOrderVO.setTotalQuantity(order.getTotalQuantity());
			list.add(flowOrderVO);

			if (order.getType() == HeadqInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
				formatTransferOrderComment(order);
				headqInventoryFlowOrderDaoImpl.evict(order);
			}
		}

		return list;
	}
	
	
	private DetachedCriteria buildSearchInvenFlowCriter(HeadqInventoryFlowFormBean formBean) {
		DetachedCriteria criteria = DetachedCriteria.forClass(HeadqInventoryFlowOrder.class);

		// 总部仓库id
		int storeId = formBean.getFlowOrder().getStoreId();
//		if (chainId != Common_util.ALL_RECORD){
//			criteria.add(Restrictions.or(Restrictions.eq("chainStore.chain_id", chainId), Restrictions.and(Restrictions.eq("toChainStore.chain_id", chainId),Restrictions.ne("status", ChainInventoryFlowOrder.STATUS_DRAFT))));
//		}

		if (storeId != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("storeId", formBean.getFlowOrder().getStoreId()));
		} else {
			criteria.add(Restrictions.or(Restrictions.eq("storeId", 1), Restrictions.eq("storeId", 2)));
		}

		int status = formBean.getFlowOrder().getStatus();
		if (status != Common_util.ALL_RECORD)
			criteria.add(Restrictions.eq("status", status));
		else
			criteria.add(Restrictions.ne("status", HeadqInventoryFlowOrder.STATUS_DELETED));

		int type = formBean.getFlowOrder().getType();
		if (type != Common_util.ALL_RECORD)
			criteria.add(Restrictions.eq("type", type));

		criteria.add(Restrictions.between("orderDate", Common_util.formStartDate(formBean.getSearchStartTime()),
				Common_util.formEndDate(formBean.getSearchEndTime())));

		return criteria;
	}

	
	private void formatTransferOrderComment(HeadqInventoryFlowOrder order) {
		HeadQInventoryStore fromChainStore = order.getFromStore();
		HeadQInventoryStore toChainStore = order.getToStore();

		String fromChainName = "非连锁店";
		String toChainName = "非连锁店";

		if (fromChainStore != null && fromChainStore.getId() != 0) {
			fromChainStore = headQInventoryStoreDAOImpl.get(fromChainStore.getId(), true);
			fromChainName = fromChainStore.getName();
			if (fromChainName.length() > 4)
				fromChainName = fromChainName.substring(0, 4);
		}
		if (toChainStore != null && toChainStore.getId() != 0) {
			toChainStore = headQInventoryStoreDAOImpl.get(toChainStore.getId(), true);
			toChainName = toChainStore.getName();
			if (toChainName.length() > 4)
				toChainName = toChainName.substring(0, 4);
		}

		String transferComment = fromChainName + " -> " + toChainName;

		String orderComment = order.getComment();
		if (orderComment.length() > 0)
			order.setComment(transferComment + "<br/>" + orderComment);
		else
			order.setComment(transferComment);

	}

	/**
	 * function to prepare the flow order ui bean for display
	 * 
	 * @param loginUser
	 * @param uiBean
	 * @param formBean
	 */
	public void prepareDisplayFlowOrderFormUIBean(UserInfor loginUser, HeadqInventoryFlowUIBean uiBean,
			HeadqInventoryFlowFormBean formBean, HeadqInventoryFlowOrder order) {
		// 添加仓库信息
		HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(order.getStoreId(), true);
		uiBean.setStoreName(store.getName());
		BaseOrder baseOrder = new BaseOrder();
		order.setStatusS(baseOrder.getStatusMap().get(order.getStatus()));
		String statusS = baseOrder.getStatusMap().get(order.getStatus());
		HeadqInventoryFlowOrder flowOrder = uiBean.getFlowOrder();
		uiBean.setFlowOrder(order);
	}

	/**
	 * 准备调货单的页面内容
	 * 
	 * @param loginUser
	 * @param uiBean
	 * @param formBean
	 * @param order
	 */
	@Transactional
	public void prepareCreateInvenTransferOrderFormUIBean(UserInfor loginUser, HeadqInventoryFlowUIBean uiBean,
			HeadqInventoryFlowFormBean formBean, HeadqInventoryFlowOrder order) {
		formBean.setFlowOrder(order);

		// 添加仓库信息
		List<HeadQInventoryStore> stores = headQInventoryStoreDAOImpl.getAll(true);
		uiBean.setStores(stores);

		// 2. set the creator
		formBean.getFlowOrder().setCreator(loginUser);

		// 3. set the date
		formBean.getFlowOrder().setOrderDate(new Date());

		// 添加调货仓库信息
		List<HeadQInventoryStore> toStores = headQInventoryStoreDAOImpl.getAll(true);
		uiBean.setToStores(toStores);

		uiBean.setToStores(toStores);

	}

	/**
	 * 保存 库存盘点单据
	 * 
	 * @param flowOrder
	 * @param loginUser
	 * @throws Exception
	 */
	@Transactional
	public Response saveInventoryToDraft(HeadqInventoryFlowOrder flowOrder, File file, UserInfor loginUser)
			throws Exception {
		Response response = new Response();

		int status_org = flowOrder.getStatus();
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			flowOrder.setStatus(HeadqInventoryFlowOrder.STATUS_DRAFT);

			List<HeadqInventoryFlowOrderProduct> products = null;
		    try {
		       products = parseInventoryFile(file, flowOrder.getStoreId());
		    } catch (Exception e) {
				response.setQuickValue(Response.FAIL, "库存文件格式错误");
				return response;
			}

			List<HeadqInventoryFlowOrderProduct> currentProducts = flowOrder.getProductList();
		    currentProducts.addAll(products);

			save(flowOrder, loginUser);
			response.setQuickValue(Response.SUCCESS, "已经成功保存");
			response.setReturnValue(flowOrder.getId());
		} else {
			response.setQuickValue(Response.FAIL, "保存草稿失败");
		}

		return response;

	}
	
	
	/**
	 * to parse the file from the inventory machine
	 * 
	 * @param inventory
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<HeadqInventoryFlowOrderProduct> parseInventoryFile(File inventoryFile, int chainId) {
		List<HeadqInventoryFlowOrderProduct> orderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();

		if (inventoryFile != null) {
			InventoryFileTemplate inventoryFileTemplate = new InventoryFileTemplate(inventoryFile);

			Response response = inventoryFileTemplate.process();
			List<Object> returnValues = (List<Object>) response.getReturnValue();
			Map<String, Integer> barcodeMap = (Map<String, Integer>) returnValues.get(0);
			Set<String> barcodes = (Set<String>) returnValues.get(1);
			Set<Integer> pbIdSet = productBarcodeDaoImpl.getPBIdsByBarcodes(barcodes);

			HeadQInventoryStore chain = headQInventoryStoreDAOImpl.get(chainId, true);

			// 2. prepare the data
			Map<String, ProductBarcode> products = productBarcodeDaoImpl.getProductMapByBarcode(barcodes);

			// 3. to get the inventory
			Map<String, Integer> inventoryMap = this.getProductsInventoryLevel(pbIdSet, chain.getId());

			for (String barcode : barcodes) {
				ProductBarcode product = products.get(barcode);

				if (product == null) {
					loggerLocal.error("Could not find the " + barcode + " in product table");
					continue;
				}

				HeadqInventoryFlowOrderProduct headqInventoryFlowOrderProduct = new HeadqInventoryFlowOrderProduct();
				headqInventoryFlowOrderProduct.setProductBarcode(product);

				Integer quantityI = barcodeMap.get(product.getBarcode());
				int quantity = 0;
				if (quantityI != null)
					quantity = quantityI.intValue();

				Integer inventoryI = inventoryMap.get(product.getBarcode());
				int inventory = 0;
				if (inventoryI != null)
					inventory = inventoryI.intValue();

				headqInventoryFlowOrderProduct.setQuantity(quantity);
				headqInventoryFlowOrderProduct.setInventoryQ(inventory);
//				headqInventoryFlowOrderProduct.setTotalSalesPrice(quantity * product.getProduct().getSalesPrice());
				headqInventoryFlowOrderProduct.setQuantityDiff(quantity - inventory);

				orderProducts.add(headqInventoryFlowOrderProduct);
			}

		}

		return orderProducts;
	}

	/**
	 * 自动纠正库存
	 * 
	 * @param flowOrder
	 * @param loginUser
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response adjustInventory(HeadqInventoryFlowOrder inventoryOrder, UserInfor loginUser) throws Exception {
		int status_org = inventoryOrder.getStatus();
		Response response = new Response();
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			inventoryOrder.setStatus(HeadqInventoryFlowOrder.STATUS_COMPLETE);

			// 1.整理order product
			groupProductList(inventoryOrder);

			// 2. 自动创建报损单，报溢单
			// 报溢单
			HeadqInventoryFlowOrder overFlowOrder = new HeadqInventoryFlowOrder();

			// 报损单
			HeadqInventoryFlowOrder flowLossOrder = new HeadqInventoryFlowOrder();

			List<HeadqInventoryFlowOrderProduct> overFlowOrderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();
			List<HeadqInventoryFlowOrderProduct> flowLossOrderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();
			List<HeadqInventoryFlowOrderProduct> inventoryOrderProducts = inventoryOrder.getProductList();
			int totalInventoryQ_overFlow = 0;
			int totalQuantity_overFlow = 0;
			int totalInventoryQ_flowLoss = 0;
			int totalQuantity_flowLoss = 0;
			for (HeadqInventoryFlowOrderProduct inventoryOrderProduct : inventoryOrderProducts) {
				int quantityDiff = inventoryOrderProduct.getQuantityDiff();
				int inventoryQ = inventoryOrderProduct.getInventoryQ();
				ProductBarcode productBarcode = inventoryOrderProduct.getProductBarcode();

				// 实际库存 > 电脑库存
				if (quantityDiff > 0) {
					HeadqInventoryFlowOrderProduct overFlowOrderProduct = new HeadqInventoryFlowOrderProduct();
					overFlowOrderProduct.setInventoryQ(inventoryQ);
					overFlowOrderProduct.setQuantity(quantityDiff);
					overFlowOrderProduct.setProductBarcode(productBarcode);
					overFlowOrderProduct.setComment("一键纠正");
					overFlowOrderProducts.add(overFlowOrderProduct);
					totalInventoryQ_overFlow += inventoryQ;
					totalQuantity_overFlow += quantityDiff;
					// 实际库存 < 电脑库存
				} else if (quantityDiff < 0) {
					HeadqInventoryFlowOrderProduct flowLossOrderProduct = new HeadqInventoryFlowOrderProduct();
					flowLossOrderProduct.setInventoryQ(inventoryQ);
					flowLossOrderProduct.setQuantity(Math.abs(quantityDiff));
					flowLossOrderProduct.setProductBarcode(productBarcode);
					flowLossOrderProduct.setComment("一键纠正");
					flowLossOrderProducts.add(flowLossOrderProduct);
					totalInventoryQ_flowLoss += inventoryQ;
					totalQuantity_flowLoss += Math.abs(quantityDiff);
				}
			}
			String msg = "";
			if (overFlowOrderProducts.size() > 0) {
				overFlowOrder.setStoreId(inventoryOrder.getStoreId());
				overFlowOrder.setCreator(loginUser);
				overFlowOrder.setOrderDate(new Date());
				overFlowOrder.setStatus(HeadqInventoryFlowOrder.STATUS_INITIAL);
				overFlowOrder.setType(HeadqInventoryFlowOrder.OVER_FLOW_ORDER);
				overFlowOrder.setTotalInventoryQ(totalInventoryQ_overFlow);
				overFlowOrder.setTotalQuantity(totalQuantity_overFlow);
				overFlowOrder.setComment("一键纠正" + inventoryOrder.getId());
				overFlowOrder.setProductList(overFlowOrderProducts);
				overFlowOrder.buildIndex();
				overFlowOrder.putListToSet();
				saveToFinal(overFlowOrder, loginUser);
				msg += "报溢单据号:" + overFlowOrder.getId() + "\n";
			}
			if (flowLossOrderProducts.size() > 0) {
				flowLossOrder.setStoreId(inventoryOrder.getStoreId());
				flowLossOrder.setCreator(loginUser);
				flowLossOrder.setOrderDate(new Date());
				flowLossOrder.setStatus(HeadqInventoryFlowOrder.STATUS_INITIAL);
				flowLossOrder.setType(HeadqInventoryFlowOrder.FLOW_LOSS_ORDER);
				flowLossOrder.setTotalInventoryQ(totalInventoryQ_flowLoss);
				flowLossOrder.setTotalQuantity(totalQuantity_flowLoss);
				flowLossOrder.setComment("一键纠正" + inventoryOrder.getId());
				flowLossOrder.setProductList(flowLossOrderProducts);
				flowLossOrder.buildIndex();
				flowLossOrder.putListToSet();
				saveToFinal(flowLossOrder, loginUser);
				msg += "报损单据号:" + flowLossOrder.getId() + "\n";
			}

			response.setReturnCode(Response.SUCCESS);
			if (msg.length() > 0)
				response.setMessage("已经成功自动生成." + msg);
			else
				response.setMessage("所有实际库存和电脑库存都匹配.无需纠正库存");
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("生成报表或者红冲的单据不能再做一键纠正");
		}

		return response;
	}

	/**
	 * the function to calculate the inventory order
	 * 
	 * @param flowOrder
	 * @return
	 */
	public Response calculateInventoryOrder(HeadqInventoryFlowOrder flowOrder) {
		Response response = new Response();

		int orderId = flowOrder.getId();

		groupProductList(flowOrder);

		if (orderId != 0) {
			HeadqInventoryFlowOrder inventoryFlowOrder = headqInventoryFlowOrderDaoImpl.get(orderId, true);
			if (inventoryFlowOrder != null) {
				inventoryFlowOrder.setProductList(flowOrder.getProductList());
				inventoryFlowOrder.setTotalInventoryQ(flowOrder.getTotalInventoryQ());
				inventoryFlowOrder.setTotalQuantity(flowOrder.getTotalQuantity());
				inventoryFlowOrder.setTotalQuantityDiff(flowOrder.getTotalQuantityDiff());

				response.setReturnCode(Response.SUCCESS);
				response.setReturnValue(inventoryFlowOrder);

				return response;
			} else {
				response.setReturnCode(Response.FAIL);
				response.setMessage("重新计算失败:原始单据无法找到");
				return response;
			}
		} else {
			response.setReturnCode(Response.SUCCESS);
			response.setReturnValue(flowOrder);
			return response;
		}
	}

	/**
	 * 获取这个盘点单中所有的年份和季度
	 * 
	 * @param inventoryOrder
	 * @return
	 */
	public Response getYearQuarterInOrder(HeadqInventoryFlowOrder inventoryOrder, List<String> yearQuarterKey) {
		List<HeadqInventoryFlowOrderProduct> productList = inventoryOrder.getProductList();
		Set<String> yearQuarter = new HashSet<String>();
		Product product = null;
		for (HeadqInventoryFlowOrderProduct orderProduct : productList) {
			if (orderProduct == null || orderProduct.getProductBarcode() == null
					|| orderProduct.getProductBarcode().getId() == 0
					|| orderProduct.getProductBarcode().getBarcode() == "")
				continue;
			product = orderProduct.getProductBarcode().getProduct();
			yearQuarter.add(product.getYear().getYear() + "-" + product.getQuarter().getQuarter_Name());
			String key = product.getYear().getYear() + "-" + product.getQuarter().getQuarter_Name();
			if (yearQuarterKey != null && !yearQuarterKey.contains(key))
				yearQuarterKey.add(key);
		}

		List<String> yearQuarterList = new ArrayList<String>(yearQuarter);
		Collections.sort(yearQuarterList);

		Response response = new Response();
		response.setReturnCode(Response.SUCCESS);
		response.setReturnValue(yearQuarterList);
		return response;
	}

	/**
	 * 将会按照这张单据成为实际库存
	 * 
	 * @param flowOrder
	 * @param loginUser
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response clearAndadjustInventory(HeadqInventoryFlowOrder inventoryOrder, UserInfor loginUser)
			throws Exception {
		int status_org = inventoryOrder.getStatus();
		Response response = new Response();
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			// 1.整理这张单据中order product
			List<HeadqInventoryFlowOrderProduct> productList = inventoryOrder.getProductList();
			// to store the sequence product id list
			Set<String> barcodeInOrder = new LinkedHashSet<String>();
			Map<String, Integer> inventoryInOrderMap = new HashMap<String, Integer>();
			for (HeadqInventoryFlowOrderProduct orderProduct : productList) {
				if (orderProduct != null) {
					ProductBarcode productBarcode = orderProduct.getProductBarcode();
					if (productBarcode != null) {
						String barcode = productBarcode.getBarcode();
						int productId = productBarcode.getId();
						if (barcode != null && !barcode.equals("") && productId != 0) {
							// 1.1 to make the order product ids
							barcodeInOrder.add(barcode);

							// 1.2 to group the product quantity
							int productQ = orderProduct.getQuantity();
							Integer inventoryObj = inventoryInOrderMap.get(barcode);

							if (inventoryObj != null) {
								inventoryInOrderMap.put(barcode, productQ + inventoryObj);
							} else {
								inventoryInOrderMap.put(barcode, productQ);
							}
						}
					}
				}
			}

			// 1.2 把这次年份和季度整理出来
			List<String> yearQuarterNames = new ArrayList<String>();
			getYearQuarterInOrder(inventoryOrder, yearQuarterNames);
			Map<String, Year> yearMap = yearDaoImpl.getYearNameMap();
			Map<String, Quarter> quarterMap = quarterDaoImpl.getQuarterNameMap();

			// 2. 获取出连锁店目前电脑存在的库存,只包含在year quarterkey里面
			Map<String, Integer> inventoryPCMap = new HashMap<String, Integer>();

			String hqlString = "SELECT i.productBarcode.id, SUM(i.quantity) FROM HeadQInventoryStock i JOIN i.productBarcode pb JOIN pb.product p  ";//

			// 做sql 拼接
			String hqlWhere = "WHERE i.storeId = " + inventoryOrder.getStoreId() + " and p.year.year_ID in ( ";
			String yearWhere = "";
			String quarterWhere = "";
			if (yearQuarterNames != null && !yearQuarterNames.isEmpty()) {

				String[] keyArray = yearQuarterNames.get(0).split("-");

				int yearKey = yearMap.get(keyArray[0]).getYear_ID();
				int quarterKey = quarterMap.get(keyArray[1]).getQuarter_ID();
				yearWhere = "" + yearKey;
				quarterWhere = "" + quarterKey;

				for (int i = 1; i < yearQuarterNames.size(); i++) {
					keyArray = yearQuarterNames.get(i).split("-");
					yearKey = yearMap.get(keyArray[0]).getYear_ID();
					quarterKey = quarterMap.get(keyArray[1]).getQuarter_ID();

					yearWhere += "," + yearKey;

					quarterWhere += "," + quarterKey;
				}
				yearWhere += ")and p.quarter.quarter_ID in (";

				hqlWhere += yearWhere;

				quarterWhere += ")";
				hqlWhere += quarterWhere;

				String sqlEnd = "GROUP BY i.productBarcode.id";

				loggerLocal.info(hqlString + hqlWhere);

				List<HeadQInventoryStock> result = headQInventoryStockDAOImpl.getByHQL(hqlString + hqlWhere + sqlEnd,
						null, true);
				for (int i = 0; i < result.size(); i++) {
					Object object = result.get(i);
					if (object != null) {
						Object[] recordResult = (Object[]) object;
						int pbId = Common_util.getInt(recordResult[0]);
						int quantity = Common_util.getInt(recordResult[1]);
						ProductBarcode pb = productBarcodeDaoImpl.get(pbId, true);
						inventoryPCMap.put(pb.getBarcode(), quantity);
					}
				}
				Set<String> barcodeInPC = new HashSet<String>();
				barcodeInPC = inventoryPCMap.keySet();

				Set<String> barcodeAll = new HashSet<String>();
				barcodeAll.addAll(barcodeInOrder);
				barcodeAll.addAll(barcodeInPC);

				// 3. 获取productbarcode 对象
				Map<String, ProductBarcode> barcodeMap = productBarcodeDaoImpl.getProductMapByBarcode(barcodeAll);

				// 3. 自动创建报损单，报溢单
				HeadqInventoryFlowOrder overFlowOrder = new HeadqInventoryFlowOrder();
				HeadqInventoryFlowOrder flowLossOrder = new HeadqInventoryFlowOrder();
				List<HeadqInventoryFlowOrderProduct> overFlowOrderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();
				List<HeadqInventoryFlowOrderProduct> flowLossOrderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();

				int totalInventoryQ_overFlow = 0;
				int totalQuantity_overFlow = 0;
				int totalInventoryQ_flowLoss = 0;
				int totalQuantity_flowLoss = 0;
				for (String barcode : barcodeAll) {
					Integer quantityInOrderObj = inventoryInOrderMap.get(barcode);
					Integer quantityInPCObj = inventoryPCMap.get(barcode);

					if (quantityInOrderObj == null && quantityInPCObj == null)
						continue;

					int quantityInOrder = quantityInOrderObj == null ? 0 : quantityInOrderObj.intValue();
					int quantityInPC = quantityInPCObj == null ? 0 : quantityInPCObj.intValue();

					int quantityDiff = quantityInOrder - quantityInPC;
					ProductBarcode productBarcode = barcodeMap.get(barcode);
					if (productBarcode == null) {
						loggerLocal.error("保存库存单据错误 : " + barcode);
						continue;
					}

					// 实际库存 > 电脑库存
					if (quantityDiff > 0) {
						HeadqInventoryFlowOrderProduct overFlowOrderProduct = new HeadqInventoryFlowOrderProduct();
						overFlowOrderProduct.setInventoryQ(quantityInPC);
						overFlowOrderProduct.setQuantity(quantityDiff);
						overFlowOrderProduct.setProductBarcode(productBarcode);
						overFlowOrderProduct.setComment("库存扎帐");
						overFlowOrderProducts.add(overFlowOrderProduct);
						totalInventoryQ_overFlow += quantityInPC;
						totalQuantity_overFlow += quantityDiff;
						// 实际库存 < 电脑库存
					} else if (quantityDiff < 0) {
						HeadqInventoryFlowOrderProduct flowLossOrderProduct = new HeadqInventoryFlowOrderProduct();
						flowLossOrderProduct.setInventoryQ(quantityInPC);
						flowLossOrderProduct.setQuantity(Math.abs(quantityDiff));
						flowLossOrderProduct.setProductBarcode(productBarcode);
						flowLossOrderProduct.setComment("库存扎帐");
						flowLossOrderProducts.add(flowLossOrderProduct);
						totalInventoryQ_flowLoss += quantityInPC;
						totalQuantity_flowLoss += Math.abs(quantityDiff);
					}
				}

				String msg = "";
				if (overFlowOrderProducts.size() > 0) {
					overFlowOrder.setStoreId(inventoryOrder.getStoreId());
					overFlowOrder.setCreator(loginUser);
					overFlowOrder.setOrderDate(new Date());
					overFlowOrder.setStatus(ChainInventoryFlowOrder.STATUS_INITIAL);
					overFlowOrder.setType(ChainInventoryFlowOrder.OVER_FLOW_ORDER);
					overFlowOrder.setTotalInventoryQ(totalInventoryQ_overFlow);
					overFlowOrder.setTotalQuantity(totalQuantity_overFlow);
					overFlowOrder.setComment("库存扎帐" + inventoryOrder.getId());
					overFlowOrder.setProductList(overFlowOrderProducts);
					overFlowOrder.buildIndex();
					overFlowOrder.putListToSet();
					saveToFinal(overFlowOrder, loginUser);
					msg += "报溢单据号:" + overFlowOrder.getId() + "\n";
				}
				if (flowLossOrderProducts.size() > 0) {
					flowLossOrder.setStoreId(inventoryOrder.getStoreId());
					flowLossOrder.setCreator(loginUser);
					flowLossOrder.setOrderDate(new Date());
					flowLossOrder.setStatus(HeadqInventoryFlowOrder.STATUS_INITIAL);
					flowLossOrder.setType(HeadqInventoryFlowOrder.FLOW_LOSS_ORDER);
					flowLossOrder.setTotalInventoryQ(totalInventoryQ_flowLoss);
					flowLossOrder.setTotalQuantity(totalQuantity_flowLoss);
					flowLossOrder.setComment("库存扎帐" + inventoryOrder.getId());
					flowLossOrder.setProductList(flowLossOrderProducts);
					flowLossOrder.buildIndex();
					flowLossOrder.putListToSet();
					saveToFinal(flowLossOrder, loginUser);
					msg += "报损单据号:" + flowLossOrder.getId() + "\n";
				}

				response.setReturnCode(Response.SUCCESS);
				if (msg.length() > 0)
					response.setMessage("已经将电脑库存清空并修正成实际库存。成功自动生成." + msg);
				else
					response.setMessage("所有实际库存和电脑库存都匹配.无需纠正库存");
			} else {
				response.setReturnCode(Response.FAIL);
				response.setMessage("生成报表或者红冲的单据不能再做一键纠正");
			}

		}
		return response;
	}

	/**
	 * function to generatet the inventory report
	 * 
	 * @param flowOrder
	 * @return
	 * @throws Exception
	 */
	@Transactional
	public Response genInventoryReport(HeadqInventoryFlowOrder flowOrder, File file, UserInfor loginUser)
			throws Exception {
		int status_org = flowOrder.getStatus();
		Response response = new Response();
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			flowOrder.setStatus(HeadqInventoryFlowOrder.STATUS_COMPLETE);

			List<HeadqInventoryFlowOrderProduct> products = null;
			try {
				products = parseInventoryFile(file, flowOrder.getStoreId());
			} catch (Exception e) {
				response.setQuickValue(Response.FAIL, "库存文件格式错误");
				return response;
			}

			List<HeadqInventoryFlowOrderProduct> currentProducts = flowOrder.getProductList();
			currentProducts.addAll(products);

			// 1. order the products by Year, Quarter, Brand
			headqInventoryFlowOrderDaoImpl.initialize(flowOrder.getProductList());

			// 1. save the order to final 过账
			save(flowOrder, loginUser);

			response.setReturnCode(Response.SUCCESS);
			response.setReturnValue(flowOrder.getId());
			response.setMessage("已经成功保存");
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("保存单据失败");
		}

		return response;
	}

	/**
	 * 获取条形码，然后生成一个inputsteam
	 * 
	 * @return
	 */
	public InputStream genBarcodeFile() {
		// 1. 准备前四年的年份
		Date today = new Date();
		int thisYear = 1900 + today.getYear();

		// 2. 新增一年
		thisYear++;

		List<String> years = new ArrayList<String>();
		for (int i = 0; i < 5; i++)
			years.add(String.valueOf(thisYear - i));

		// 2. 获取前四年的year
		List<Year> years2 = yearDaoImpl.getYear(years);

		List<ProductBarcode> productBarcodes = productBarcodeDaoImpl.getBarcodeByYear(years2);
		StringBuffer barcodeBuffer = new StringBuffer();

		String barcode = "";
		String productCode = "";
		String brandName = "";
		Color color = null;
		String colorName = "";
		for (ProductBarcode productBarcode : productBarcodes) {
			barcode = productBarcode.getBarcode();
			productCode = productBarcode.getProduct().getProductCode();
			brandName = productBarcode.getProduct().getBrand().getBrand_Name();
			color = productBarcode.getColor();
			if (color != null)
				colorName = color.getName();

			barcodeBuffer.append(barcode + "," + productCode + "," + brandName + "," + colorName + "," + "\n");
			// barcodeBuffer.append(productBarcode.getId() + ",1"+ "\n" );
		}

		ByteArrayInputStream is = new ByteArrayInputStream(barcodeBuffer.toString().getBytes());
		return is;
	}

	/**
	 * function to save the flow order to draft order 保存草稿
	 * 
	 * @param flowOrder
	 * @throws Exception
	 */
	@Transactional
	public Response saveToDraft(HeadqInventoryFlowOrder flowOrder,File file, UserInfor loginUser) throws Exception {
		int status_org = flowOrder.getStatus();
		Response response = new Response();
		
		if (flowOrder.getType() == HeadqInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
			flowOrder.setStoreId(flowOrder.getFromStore().getId());
		} else {
			flowOrder.setStoreId(flowOrder.getStoreId());
		}
		
		if (status_org == HeadqInventoryFlowOrder.STATUS_INITIAL
				|| status_org == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			flowOrder.setStatus(HeadqInventoryFlowOrder.STATUS_DRAFT);

			List<HeadqInventoryFlowOrderProduct> products = null;
			try {
		       products = parseInventoryFile(file);
			} catch (Exception e) {
				response.setQuickValue(Response.FAIL, "库存文件格式错误");
				return response;
			}

			List<HeadqInventoryFlowOrderProduct> currentProducts = flowOrder.getProductList();
		    currentProducts.addAll(products);

			save(flowOrder, loginUser);
			response.setReturnCode(Response.SUCCESS);
			response.setMessage("已经成功保存");
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("保存草稿失败");
		}

		return response;

	}

	/**
	 * the function to delete the order by mark the order status to deleted
	 * 
	 * @param orderId
	 * @param loginUser
	 */
	public Response deleteOrderById(int orderId, UserInfor loginUser) {
		Response response = new Response();
		HeadqInventoryFlowOrder flowOrder = headqInventoryFlowOrderDaoImpl.get(orderId, true);

		if (flowOrder.getStatus() == HeadqInventoryFlowOrder.STATUS_DRAFT) {
			String hql = "UPDATE HeadqInventoryFlowOrder c SET c.status=? WHERE c.id=?";
			Object[] values = new Object[] { HeadqInventoryFlowOrder.STATUS_DELETED, orderId };

			int count = headqInventoryFlowOrderDaoImpl.executeHQLUpdateDelete(hql, values, true);

			if (count == 0) {
				response.setReturnCode(Response.FAIL);
				response.setMessage("删除单据失败");
			} else {
				response.setReturnCode(Response.SUCCESS);
				response.setMessage("成功删除单据");
			}
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("过账的单据无法删除");
		}

		return response;
	}

	@Transactional
	public Response downloadFlowOrder(int id, UserInfor loginUser) throws Exception {
		Response response = new Response();
		List<Object> values = new ArrayList<Object>();

		String webInf = this.getClass().getClassLoader().getResource("").getPath();
		String contextPath = webInf.substring(1, webInf.indexOf("classes")).replaceAll("%20", " ");

		HeadqInventoryFlowOrder order = getOrderById(id, loginUser);
//		if (order.getType() ==  ChainInventoryFlowOrder.INVENTORY_TRANSFER_ORDER){
//			formatTransferOrderComment(order);
//			chainInventoryFlowOrderDaoImpl.evict(order);
//		}

		if (order.getType() == HeadqInventoryFlowOrder.OVER_FLOW_ORDER) {
			order.setTypeHQS("总部库存报溢单");
		}
		if (order.getType() == HeadqInventoryFlowOrder.FLOW_LOSS_ORDER) {
			order.setTypeHQS("总部库存报溢单");
		}
		boolean showCost = loginUser.containFunction("purchaseAction!seeCost");

		ByteArrayInputStream byteArrayInputStream;
		HSSFWorkbook wb = null;
		HeadQInventoryStore store = headQInventoryStoreDAOImpl.get(order.getStoreId(), true);
		HeadqInventoryFlowOrderTemplate flowOrderTemplate = new HeadqInventoryFlowOrderTemplate(order, store,
				contextPath + "template\\", showCost);
		wb = flowOrderTemplate.process();

		ByteArrayOutputStream os = new ByteArrayOutputStream();
		wb.write(os);

		byte[] content = os.toByteArray();
		byteArrayInputStream = new ByteArrayInputStream(content);

		values.add(byteArrayInputStream);
		values.add(order.getTypeHQS());
		response.setReturnValue(values);

		return response;
	}
	
	
	/**
	 * to parse the file from the inventory machine
	 * 
	 * @param inventory
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<HeadqInventoryFlowOrderProduct> parseInventoryFile(File inventoryFile) {
		List<HeadqInventoryFlowOrderProduct> orderProducts = new ArrayList<HeadqInventoryFlowOrderProduct>();

		if (inventoryFile != null) {
			InventoryFileTemplate inventoryFileTemplate = new InventoryFileTemplate(inventoryFile);

			Response response = inventoryFileTemplate.process();
			List<Object> returnValues = (List<Object>) response.getReturnValue();
			Map<String, Integer> barcodeMap = (Map<String, Integer>) returnValues.get(0);
			Set<String> barcodes = (Set<String>) returnValues.get(1);

			// 2. prepare the data
			Map<String, ProductBarcode> products = productBarcodeDaoImpl.getProductMapByBarcode(barcodes);

			for (String barcode : barcodes) {
				ProductBarcode product = products.get(barcode);

				if (product == null) {
					loggerLocal.error("Could not find the " + barcode + " in product table");
					continue;
				}

				HeadqInventoryFlowOrderProduct headqInventoryFlowOrderProduct = new HeadqInventoryFlowOrderProduct();
				headqInventoryFlowOrderProduct.setProductBarcode(product);

				Integer quantityI = barcodeMap.get(product.getBarcode());
				int quantity = 0;
				if (quantityI != null)
					quantity = quantityI.intValue();

				headqInventoryFlowOrderProduct.setQuantity(quantity);

				orderProducts.add(headqInventoryFlowOrderProduct);
			}

		}

		return orderProducts;
	}

	/**
	 * function to cancel the flow order 红冲
	 */
	@Transactional
	public Response cancelOrder(int orderId, UserInfor loginUser) {
		HeadqInventoryFlowOrder flowOrder = getOrderById(orderId, loginUser);
		int status_org = flowOrder.getStatus();
		Response response = new Response();
		if (status_org == HeadqInventoryFlowOrder.STATUS_COMPLETE) {
			// 1. 红冲单据，修改状态
			String hql = "UPDATE HeadqInventoryFlowOrder c SET c.status=? WHERE c.id=?";
			Object[] values = new Object[] { ChainInventoryFlowOrder.STATUS_CANCEL, orderId };

			int count = headqInventoryFlowOrderDaoImpl.executeHQLUpdateDelete(hql, values, true);

			if (count == 0) {
				response.setReturnCode(Response.FAIL);
				response.setMessage("红冲单据失败");
			} else {
				// 2. 修改stock in/out table
				// 只有报溢单,报损单，调货单可以
				if (flowOrder.getType() == HeadqInventoryFlowOrder.FLOW_LOSS_ORDER
						|| flowOrder.getType() == HeadqInventoryFlowOrder.OVER_FLOW_ORDER) {
					updateHeadqFlowOrderInOutStock(flowOrder, ChainStoreSalesOrder.STATUS_CANCEL);
				} else if (flowOrder.getType() == ChainInventoryFlowOrder.INVENTORY_TRANSFER_ORDER) {
//		    		   updateChainInvenTransferInOutStock(flowOrder, ChainStoreSalesOrder.STATUS_CANCEL);  调货单红冲
				}

				response.setReturnCode(Response.SUCCESS);
				response.setMessage("成功红冲单据");
			}
		} else {
			response.setReturnCode(Response.FAIL);
			response.setMessage("只有过账的单据可以红冲");
		}

		return response;
	}
	
}
